package cn.nextProject.service.minio;

import cn.nextProject.configs.MinioConfig;
import cn.nextProject.entity.FileResult;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class MinioService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfig minioConfig;

    /**
     * 验证桶是否存在
     * @param bucketName
     * @return
     * @throws Exception
     */
    public boolean isExist(String bucketName) throws Exception {
        // 验证存储桶是否存在
        return minioClient.bucketExists(
                BucketExistsArgs.builder().bucket(bucketName).build());

    }

    /**
     * 文件/文件夹重命名
     * @param buckName
     * @param oldPath
     * @param newPath
     */
    @CacheEvict(cacheNames = "bucketList",allEntries = true,beforeInvocation = true)
    public void renameFile(String buckName,String oldPath,String newPath) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {

        // 复制文件到新路径
        minioClient.copyObject(
                CopyObjectArgs.builder()
                        .bucket(buckName)
                        .object(newPath)
                        .source(CopySource.builder()
                                .bucket(buckName)
                                .object(oldPath)
                                .build())
                        .build()
        );

        // 删除原文件（关键补充）
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(buckName)
                        .object(oldPath)
                        .build()
        );

    }

    /**
     * 文件/文件夹重命名
     * @param fileResultList
     */
    @CacheEvict(cacheNames = "bucketList",allEntries = true,beforeInvocation = true)
    public void removeFile(List<FileResult> fileResultList) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {

        for (FileResult fileResult : fileResultList) {
            // 复制文件到新路径
            minioClient.copyObject(
                    CopyObjectArgs.builder()
                            .bucket(fileResult.getBucketName())
                            .object(fileResult.getRemoveObjectName())
                            .source(CopySource.builder()
                                    .bucket(fileResult.getBucketName())
                                    .object(fileResult.getObjectName())
                                    .build())
                            .build()
            );

            // 删除原文件（关键补充）
            minioClient.removeObject(
                    RemoveObjectArgs.builder()
                            .bucket(fileResult.getBucketName())
                            .object(fileResult.getObjectName())
                            .build()
            );
        }

    }

    /**
     * 移动文件位置
     * @param fileResultList
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    @CacheEvict(cacheNames = "bucketList",allEntries = true,beforeInvocation = true)
    public void removeObjects(List<FileResult> fileResultList) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {

        for (FileResult fileResult : fileResultList) {


        }

    }

    /**
     * 验证目录/文件是否存在
     * @param bucketName
     * @param filename
     * @return
     * @throws Exception
     */
    public boolean isFile(String bucketName, String filename){
        try {
            StatObjectResponse stat = minioClient.statObject(
                    StatObjectArgs.builder()
                            .bucket(bucketName)
                            .object(filename)
                            .build()
            );
            return true; // 存在时返回 true
        } catch (ErrorResponseException e) {
            if (e.errorResponse().code().equals("NoSuchKey")) {
                return false; // 文件不存在
            }
            throw new RuntimeException("MinIO 异常: " + e.getMessage());
        } catch (Exception e) {
            throw new RuntimeException("未知错误: " + e.getMessage());
        }
    }

    // 删除多个文件
    @CacheEvict(cacheNames = "bucketList",allEntries = true,beforeInvocation = true)
    public void deleteObjects(List<FileResult> fileResultList) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        for (FileResult fileResult : fileResultList) {
            String bucketName = fileResult.getBucketName();
            String lastPath = fileResult.getLastPath();
            String name = fileResult.getName();
            if (ObjectUtils.isEmpty(bucketName)){
                continue;
            }

            if (ObjectUtils.isEmpty(name)){
                continue;
            }

            String objectPrefix = Stream.of(fileResult.getLastPath(), fileResult.getName())
                    .filter(StringUtils::hasText)
                    .collect(Collectors.joining("/"));

            // 处理目录删除
            if (fileResult.isDir()) {
                Iterable<Result<Item>> objects = minioClient.listObjects(
                        ListObjectsArgs.builder()
                                .bucket(bucketName)
                                .prefix(objectPrefix + "/") // 添加斜杠确保精确匹配目录
                                .recursive(true).build());

                for (Result<Item> object : objects) {
                    minioClient.removeObject(
                            RemoveObjectArgs.builder()
                                    .bucket(bucketName)
                                    .object(object.get().objectName())
                                    .build());
                }
            } else { // 处理文件删除
                minioClient.removeObject(
                        RemoveObjectArgs.builder()
                                .bucket(bucketName)
                                .object(objectPrefix).build());
            }
        }
    }

    /**
     * 创建桶（bucket）
     * @param bucketName
     */
    public void createBucket(String bucketName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {

        if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())){
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());;
        }

    }

    /**
     * 创建文件夹（bucket）
     * @param fileResult
     */
    @CacheEvict(cacheNames = "bucketList",allEntries = true,beforeInvocation = true)
    public void createFolder(FileResult fileResult) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        // 规范路径生成
        String normalizedPath = fileResult.getLastPath().replaceAll("/$", "");
        String objectKey = String.format("%s/%s/", normalizedPath, fileResult.getName());

        PutObjectArgs args = PutObjectArgs.builder()
                .bucket(fileResult.getBucketName())
                .object(objectKey)
                .stream(new ByteArrayInputStream(new byte[0]), 0, -1)
                .build();

        try {
            minioClient.putObject(args); // 执行上传操作
        } catch (Exception e) {
            throw new RuntimeException("文件夹创建失败: " + e.getMessage());
        }
    }

    /**
     * 上传文件到minio（指定的桶中）
     * @param bucketName
     * @param file
     * @return
     * @throws IOException
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    public String uploadFile(String bucketName, MultipartFile file) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        String extName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")) ;
        String fileName = UUID.randomUUID().toString() + extName ;
        log.info("上传文件名：{}",fileName);
        minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName)
                .stream(file.getInputStream(),file.getSize(),-1)
                .contentType(file.getContentType()).build()) ;
        return minioConfig.getEndpoint() + "/" + bucketName + "/" + fileName ;//返回文件所在路径
    }

    public String upLoadFiles(String bucketName, List<MultipartFile> files, String lastPath) throws IOException, ServerException, InsufficientDataException, ErrorResponseException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        if (CollectionUtils.isEmpty(files)){
            log.info("无上传文件！");
            return "无上传文件！";
        }
        for (MultipartFile file : files) {
            minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(lastPath + "/" + file.getName())
                    .stream(file.getInputStream(),file.getSize(),-1)
                    .contentType(file.getContentType()).build()) ;
        }
        return "上传成功！";
    }

    /**
     * 下载文件（指定桶内文件）
     * @param bucketName
     * @param filename
     * @return
     * @throws Exception
     */
    public InputStream downloadFile(String bucketName, String filename) throws Exception {
        return minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(filename)
                .build());
    }

    // 检查 Bucket 是否存在
    public boolean bucketExists(String bucketName) throws Exception {
        return minioClient.bucketExists(
                BucketExistsArgs.builder().bucket(bucketName).build()
        );
    }


}
